/*

Silly.C by Bill Buckels 2008.

Written by   : Bill Buckels
Email        : bbuckels@mts.net

Date Written : May 2008

Environment  : AppleX Manx Aztec C65 Version 3.2b
Windows XP Cross-development environment for ProDOS 8

I have made absolutely no attempt to make this program compatible
with any C compiler outside the AppleX environment stated above.

Purpose Graphics Demo and Children's Play Activity

This program is based on "The Mixed-Up Toy game" from Broderbund's
PlayRoom program. "Three different sections of the body--the head,
torso, and legs spin around and its up to the kids to change the
body parts to match the cartoon characters."

It also offers a BSAVE option to save the Silly Things.

Please see the User Documentation for further details.

Licence Agreement
-----------------

All my work is copyrighted and belongs to me. I wrote this program
from scratch. However this program is a derivative work in pretty
much every way.

That notwithstanding this is also a programming demo for an obsolete
computer and a vanished market. The original Copyright remains in
place and is displayed on the title screen when the program loads.

I herewith grant you a non-exclusive and conditional licence to use
this program, the source code and the output files it produces for
whatever use you deem fit provided you do not take credit for my
work, and that you leave the copyright notices intact in all of it.

If you augment or otherwise use my work you must always also include
your own personal copyright notice but it may never be a GNU public
licence or anything else that resembles fascism or totalitarianism
and world-domination or a commercial or educational licence either.
You can use my stuff commercially or for GNU with my conditions
intact if they let you (they should since copyright is for authors
and the public and I belong to both groups) but you must never
copyright my work with any company copyright whatsoever; just your
own personal copyright like mine and leave mine in place. That is the
way copyright is intended to work and that is the way that it will
work with my stuff unless I selectively decide otherwise.

In addition you must agree that I am not liable in any way shape or
form for any damage from the use of any of this in any way
whatsoever.

If you do not agree with all of the aforementioned conditions of use
then remove all of this from your computer now.

Bill Buckels
bbuckels@mts.net
May 2008

*/

#include <fcntl.h>
#include <stdio.h>

FILE *piclist=NULL;

/* G2 library extern */
extern unsigned HB[];

#define RAX_MAX 1607
#define ENGLISH 0
#define FRENCH 1

int language=ENGLISH;

/* 10 static silly things */
char *sillies[10] = {
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL};

char *enames[10] = {
	"DRAGON",
	"ROBOT",
	"CARROT",
	"RHINO",
	"ELEPHANT",
	"CLOWN",
	"FAIRY",
	"MOUSE",
	"FISH",
	"UNICORN"};

char *fnames[10] = {
	"DRAGON",
	"ROBOT",
	"CAROTTE",
	"RHINOCEROS",
	"ELEPHANT",
	"CLOWN",
	"FAIRY",
	"MOUSE",
	"FISH",
	"UNICORN"};

char *putdisk = NULL;
char *eputdisk = "Put Data Disk into drive...";
char *fputdisk = "CHANGEZ A LA DISQUETTE DE DONNEES.";

char *saveprompt = NULL;
char *esaveprompt = "SPACE to SAVE.";
char *fsaveprompt = "LA TOUCHE D'ESPACE POUR COPIER.";

char *savenot = NULL;
char *esavenot = "Any other key to continue...";
char *fsavenot = "UNE TOUCHE D'AUTRE POUR CONTINUER.";

char *wait = NULL;
char *ewait = "Please Wait...";
char *fwait = "UNE MOMENT SVP...";

char *openerr = NULL;
char *eopenerr = "ERR Could not open...";
char *fopenerr = "ERR NE POURRAIT PAS OUVRIR...";

char *writerr = NULL;
char *ewriterr = "ERR Could not write...";
char *fwriterr = "ERR NE POURRAIT PAS ECRIRE...";

char *saveok = NULL;
char *esaveok = "Saved Silly Thing...";
char *fsaveok = "LE FARFELUE A ETE COPIEE AVEC SUCCES.";

char *putprog = NULL;
char *eputprog ="Put Program Disk into drive...";
char *fputprog ="CHANGEZ A LA DISQUETTE DE LOGICIEL.";

char *anykey = NULL;
char *eanykey ="Any key to continue...";
char *fanykey ="APPUYEZ SUR UNE TOUCHE POUR CONTINUER.";

char *menu1 = NULL;
char *menu2 = NULL;

char *emenu1 = "TOP  '1'       MIDDLE '2'    BOTTOM '3'";
char *emenu2 = "MENU=SPACEBAR  FRENCH 'F'      SAVE 'S'";

char *fmenu1 = "LA TETE '1'    LE TORSE '2'  LE BAS '3'";
char *fmenu2 = "LE MENU=ESPACE  ANGLAIS 'A'  COPIER 'C'";


/* title is not used */
char *etitle = "1000 Silly Things";
char *ftitle = "1000 caricatures farfelues";


/* indices for top, middle, and bottom */
int tidx = 0, midx = 0, bidx = 0;
int todx = 0, modx = 0, bodx = 0;

/* screen co-ordinates xorg, yorg */
/* no room is available to persist a program title signature */
/* for saved images */
/* it's just too complicated */
int sorg[3][2] = {
	3,0,
	3,64,
	3,134};

/* a read buffer */
unsigned char raxbuf[RAX_MAX];
unsigned char sillyname[41], proname[41], picname[66];

int bottom = 0;


main()
{
	int c;


    /* first get the language */
    /* and setup the strings for either english or french */
    language = get_language();
    init_strings();

	setcrtmode(2);

    /* don't allow languge to change at the title screen level for now */

	if (getch()!=27) {
		/* set-up initial screen */
		clear_bottom();
		setmem(0x4000,0x2000,0xff); /* white */
		show_silly(0);
		show_silly(1);
		show_silly(2);
		print_bottom(menu1,0,0);
		print_bottom(menu2,1,0);
		/* save line 2 for additional messages etc. */
		bottom = 1;
		mscreen(); /* start in mixed screen */

		for (;;) {
			c = toupper(getch());
			if (c == 27)break;
            /* remap keys */
			switch(c)
			{
				/* left and right arrow */
				/* letter M */
				case 77:
				case 21:
				case 8:
				        c =50; break; /* both remap to 2 */
				/* uparrow remaps to 1 */
				/* letter T */
				case 84:
				case 11: c = 49; break;

                /* down arrow */
                /* letter B */
                case 66:
				case 10: c = 51; break;
				default: break;
			}

		    /* menu */
			if (c == 49 || c == 50 || c == 51) {
				show_silly(c-49);
			}
			if (c == 13 || c == 32) {
				if (bottom == 0) {
					mscreen();
					bottom = 1;
				}
				else {
					fscreen();
					bottom = 0;
				}
			}
			if (c == 'S' || c == 'C')save_silly();
			if (c == 'F' || c == 'A' || c == 'E') flip_language(c);
		}

	}
	setcrtmode(0);
    _exit();

}


/* save as an Apple II BSaved Image
   so it can be loaded in BASIC
   or viewed in other programs */
int save_silly()
{
	int c, idx, oldbot = bottom, found = 0;

	clear_bottom();
	if (oldbot != 1)mscreen();
	bottom = 1;
	print_bottom(putdisk,0,0);
	print_bottom(saveprompt,1,0);
	print_bottom(savenot,2,0);
	print_bottom(sillyname,3,0);

    c = getch();
    if (c == 13 || c == 32) {
		clear_bottom();
		print_bottom(wait,0,0);
		print_bottom(sillyname,3,0);
		c = bsave(proname);
		switch(c) {
			case -1: print_bottom(openerr,0,0); bell(); break;
			case -2: print_bottom(writerr,0,0); bell();break;
			default:

                     piclist=fopen("PICLIST","r");

                     if (piclist != NULL) {
						 fgets(picname,66,piclist); /* get the first filename */
						 while(picname[0]>' ' && picname[0] < '{')
						 {
						      idx=0;  /* replace carriage return with null */
						      while(picname[idx]!=0)
						      {
						      	if(picname[idx]< ' ')
						      	{
									picname[idx]= 0;
									break;
								}
						      	idx++;
						      }
						      idx=0;
						      found = 1;
							  while(proname[idx]!=0)
						      {
							  	 if(picname[idx] != proname[idx])
							  	 {
									 found = 0;
									 break;
								 }
							  	 idx++;
						      }
						      if (found == 1)break;
						      fgets(picname,66,piclist);
                          }
                          fclose(piclist);

				     }
				     piclist = NULL;
				     if (found == 0) {
			         	piclist=fopen("PICLIST","a");
			         	if (piclist != NULL) {
						 	fprintf(piclist,"%s\n",proname);
						 	fclose(piclist);
					 	}
					 	piclist = NULL;

				 	 }
					 print_bottom(saveok,0,0);

		}
		print_bottom(putprog,1,0);
		print_bottom(anykey,2,0);
		getch();

	}
	else c = 0;

    if (oldbot != 1)fscreen();
    bottom = oldbot;
    clear_bottom();
    print_bottom(menu1,0,0);
	print_bottom(menu2,1,0);
	print_bottom(sillyname,3,0);

	return c;

}


int get_language()
{
	int c, lang;

    lang = -1;
   	piclist = NULL;
   	piclist = fopen("SILLYLANG","r");

   	if (piclist != NULL) {
	  c = fgetc(piclist);
	  if (c == EOF) c = 255;
	  c = toupper(c);
	  if (c == 'E' || c == 'A')lang = 0;
	  if (c == 'F') lang = 1;
	  fclose(piclist);
	  piclist = NULL;
	}

	if (lang == -1)lang = language;

    return lang;
}

int set_language()
{

	int c, lang;

    lang = -1;
   	piclist = NULL;

    if (language == 1) c = 'F';
    else c = 'E';

   	piclist = fopen("SILLYLANG","w");

   	if (piclist != NULL) {
	  lang = language;
	  fprintf(piclist,"%c\n",c);
	  fclose(piclist);
	  piclist = NULL;
	}

    return lang;
}

int init_strings()
{
     int idx;

     for (idx = 0; idx < 10; idx++) {
		 if (language == FRENCH) sillies[idx] = fnames[idx];
		 else sillies[idx] = enames[idx];
	 }

     if (language == FRENCH) {
	    putdisk = fputdisk;
		saveprompt = fsaveprompt;
		savenot = fsavenot;
        wait = fwait;
        openerr = fopenerr;
        writerr = fwriterr;
        saveok = fsaveok;
        putprog = fputprog;
        anykey = fanykey;
        menu1 = fmenu1;
        menu2 = fmenu2;
	 }
	 else {
	    putdisk = eputdisk;
		saveprompt = esaveprompt;
		savenot = esavenot;
        wait = ewait;
        openerr = eopenerr;
        writerr = ewriterr;
        saveok = esaveok;
        putprog = eputprog;
        anykey = eanykey;
        menu1 = emenu1;
        menu2 = emenu2;
	 }
     return 0;
}

int flip_language(lang)
int lang;
{
	int templang = -1, idx;

	if ((lang == 'E' || lang == 'A') && language != ENGLISH) templang = ENGLISH;
	if (lang == 'F' && language != FRENCH) templang = FRENCH;

	if (templang !=  -1) {
		language = templang;
		init_strings();
		set_language();
		print_bottom(menu1,0,0);
		print_bottom(menu2,1,0);
	    for (idx = 0; idx < 40; idx++)sillyname[idx] = 32;
	    sillyname[40] = 0;
	    print_bottom(sillyname,3,0);
        strcpy(sillyname,(char *)&sillies[todx][0]);
        strcat(sillyname,".");
        strcat(sillyname,(char *)&sillies[modx][0]);
        strcat(sillyname,".");
        strcat(sillyname,(char *)&sillies[bodx][0]);
 	    print_bottom(sillyname,3,0);
	}
	return templang;

}

/* display the image fragment in its
   logical position */
int show_silly(sidx)
int sidx;
{
	int xorg, yorg,c,idx;
	char fname[20];

	if (tidx > 9)tidx = 0;
	if (midx > 9)midx = 0;
	if (bidx > 9)bidx = 0;

	/* the filename is always in english regardless of language */
	/* in the case of recognizing the saved french files afterwards:

			DRAGON=DRAGON
			ROBOT=ROBOT
			CAROTTE=CARROT - CAROTTE will gain a second R.
			RHINOCEROS=RHINO - truncates to RHINO
			ELEPHANT=ELEPHANT
			CLOWN=CLOWN
			FEE=FAIRY - unrecognizable
			SOURIS=MOUSE - unreconizable
			POISSON=FISH - unrecognizable
			LICORNE=UNICORN	- somewhat recognizable

	   While this compromises the french in 60% of the set
	   this is a programming consideration to avoid a number of
	   potential problems and to make programming easier:

	   1. The initial compressed image fragments require a relatively
	      large amount of disk space despite the fact that they are
	      compressed. It is not practical to add 60% more image fragment
	      files (additional duplicates) that are named in french so that
	      our loader uses a differently named file. It serves no purpose
	      except that a french person looking at the disk would see
	      the extra files in french. They would still see the english files,
	      so doing this would serve no real purpose and also would
	      add unecessary code to the program without improving the user
	      experience.

	   2. Adding 6 files would increase the number of combinations
	      from 10 x 10 x 10 = 1000 to 16 x 16 x 16 = 4096 and would also result
	      in potential duplicates of 3096 files if the program was flipped
	      between English and French.  And "4096 Silly Things" does not have
	      the same "ring" to a child's ear as "1000 Silly Things".

	   A potential elegant workaround for most of this would be to rename
	   the initial compressed files "on the fly" every time the language
	   is changed. However there are a couple of reasons why this would not
	   be a good idea:


	   1. If a program was flipped back and forth between English and French
	      duplicate output files could still occur. The potential for this
	      happening can't be ignored and since the user experience would
	      not be improved because the filename never appears on screen
	      anyway. If the same program is shared between users this might
	      be more likely to happen.

	   2. Whenever disk level commands are done, there is both a risk of
	      corruption and error checking code must be added. When loading or
	      saving error checking is simple and already in place. Yes the
	      program does depend on the initial image fragments all being available
	      to read and there is a risk that this may not be the case, but the
	      program will still work with some files missing the way I have
	      programmed it, and I distributed a functional disk image with
	      everything in place, and loading files is a read operation, not
	      a write operation.

	      If I start renaming things, it's like saving a file. Except when
	      a file save goes bad it's because the disk is full or corrupt
	      or because the volume label (ProDOS) has changed from that
	      of the program disk (Program and Data Disks require the same name
	      in ProDOS).

	      I don't see the benefit in renaming warranting all the extra
	      code that I would need to write, and also to base the architecture
	      on a rename command (a write operation) would unecessarily complicate
	      the program logic, complicate testing, and all associated code.
	      It's just not a clean solution and having explained enough of my
	      reasons that you might understand, 'nuff said.

	    */

	switch(sidx)
	{
		case 0: strcpy(fname,(char *)&enames[tidx][0]);
		        strcat(fname,"1.RAX");
		        todx = tidx;
		        tidx++;
		        break;
		case 1: strcpy(fname,(char *)&enames[midx][0]);
		        strcat(fname,"2.RAX");
		        modx = midx;
		        midx++;
		        break;
		case 2: strcpy(fname,(char *)&enames[bidx][0]);
		        strcat(fname,"3.RAX");
		        bodx = bidx;
		        bidx++;
		        break;

		default: return 0;

	}
	c = read_bin(fname,raxbuf);
	if(c== 0) {
        /* the new name will display if in mixed screen mode
           otherwise they can press the spacebar to toggle
           between fullscreen and mixed screen and they will
           see it then

		ProDOS allowed only fifteen characters in a
		filename compared to Apple DOS's thirty.

					*/

	    xorg = sorg[sidx][0];
	    yorg = sorg[sidx][1];
	    for (idx = 0; idx < 40; idx++)sillyname[idx] = 32;
	    sillyname[40] = 0;
	    print_bottom(sillyname,3,0);
        strcpy(sillyname,(char *)&sillies[todx][0]);
        strcpy(proname,(char *)&enames[todx][0]);
        proname[5]=0;
        strcat(sillyname,".");
        strcat(sillyname,(char *)&sillies[modx][0]);
        strcat(proname,(char *)&enames[modx][0]);
        proname[10]=0;
        strcat(sillyname,".");
        strcat(sillyname,(char *)&sillies[bodx][0]);
        strcat(proname,(char *)&enames[bodx][0]);
        proname[15]=0;
	    print_bottom(sillyname,3,0);
	    put_rax(raxbuf,xorg,yorg);

	}
	else {
		bell();
	}
	return c;


}

/* read a RAX file */
int read_bin(name,ptr)
char *name, *ptr;
{

   int fh, c=-1, limit = RAX_MAX +1, width, height;
   char head[2];

   fh = open(name,O_RDONLY,0xc3);
   if (fh == -1)return -1;
   c = read(fh,head, 2);
   if (c==2 && head[0] > 0 && head[1] > 0 && head[0] < 41 && head[1] < 193) {
	   c = read(fh,(char *)&ptr[2],RAX_MAX);
	   ptr[0] = head[0];
	   ptr[1] = head[1];
	   if (c > 0)c=0;
	   else c=-2;
   }
   else c = -2;
   close(fh);
   return c;
}

